package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"lark/src/evaluator"
	"lark/src/exception"
	"lark/src/lexer"
	"lark/src/object"
	"lark/src/parser"
	"lark/src/repl"
	"lark/utils"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
)

const MONKEY_FACE = `
    ___       ___       ___       ___   
   /\__\     /\  \     /\  \     /\__\  
  /:/  /    /::\  \   /::\  \   /:/ _/_ 
 /:/__/    /::\:\__\ /::\:\__\ /::-"\__\
 \:\  \    \/\::/  / \;:::/  / \;:;-",-"
  \:\__\     /:/  /   |:\/__/   |:|  |  
   \/__/     \/__/     \|__|     \|__|  

`

const VERSION = "0.1.0"
const HEADER = "Lark " + VERSION + "\n"
const PROMPT = "lark >>"

func main() {
	if len(os.Args) > 1 {
		//打开lark.exe并获取命令
		// args := os.Args[1:]
		args := os.Args
		//字符串中是否包含 'lark'
		isLark := strings.Contains(args[0], "lark")
		if isLark {

			switch args[1] {
			case "-r":
				// run 运行
				//从文件中获取
				// fmt.Println(args[2])
				var runFilesPath string
				if len(args) == 3 {
					runFilesPath = args[2]
				}

				errorManager := exception.NewErrorManager()
				//创建符号表
				env := object.NewEnvironment()
				evaluator.NewEvaluator(env, errorManager)

				// 运行
				Run(runFilesPath, env, "file", errorManager)
			case "-p":
				// package 打包
				// 获取当前工作目录
				currentDir, errs := os.Getwd()
				if errs != nil {
					log.Fatal(errs)
				}
				projectName := ""
				if len(args) == 3 {
					//输入名称后使用名称做为exe文件名
					projectName = args[2]
				} else {
					//打包时获取项目名称做为exe文件名
					// 使用 Split 函数以'\'为分隔符将其分割成字符串切片
					fruits := strings.Split(currentDir, "\\")
					// 项目名称,获取切片的最后一个元素
					projectName = fruits[len(fruits)-1]
				}

				/**
				 * args[0] 为编译器lark.exe的路径
				 * lark.exe的路径替换为 package.exe可执行文件的路径
				 */
				orgFilePath := strings.Replace(args[0], "lark.exe", "\\execution\\execution.exe", 1)
				//新的可执行文件路径
				targetFilePath := currentDir + "\\" + projectName + ".exe"

				//复制文件到项目目录
				utils.CopyFile(orgFilePath, targetFilePath)

				/* // 创建命令对象
				cmd := exec.Command(targetFilePath, "lark", currentDir+"\\"+args[2])
				// 执行命令
				err := cmd.Run()
				if err != nil {
					fmt.Println("无法打开指定的.exe文件:", err)
					os.Exit(1)
				} */

			case "build":
				// build 构建项目
				// exec.Command("./build.exe", "lark", "build", args[2]).Run()
				fmt.Println("./build.exe", "build", args[2])

				// 安全地构建参数列表
				// args := []string{"build", args[2]}

				var cmd *exec.Cmd
				cmd = exec.Command("cmd", "/c", "build.exe", "build", args[2])
				// 尝试以管理员身份运行
				/*
					if runtime.GOOS == "windows" {
					} else {
						cmd = exec.Command("./build.exe", "build", args[2])
					} */

				var stdout, stderr bytes.Buffer
				cmd.Stdout = &stdout
				cmd.Stderr = &stderr
				err := cmd.Run()
				if err != nil {
					fmt.Printf("错误: %v\n", err)
					fmt.Printf("标准输出: %s\n", stdout.String())
					fmt.Printf("标准错误: %s\n", stderr.String())
					return
				} else {
					// 命令执行成功
					fmt.Println("命令执行成功")
					fmt.Println("输出结果:", stdout.String())
				}

				/* if err := build.Build(args[2], utils.DefaultOutputName(args[2])); err != nil {
					fmt.Fprintf(os.Stderr, "Error: %v\n", err)
					os.Exit(1)
				} */
			case "-v":
				// version 查看版本号
				fmt.Println(HEADER)
			case "-h":
				//help 输出帮助信息

			}
		}
	} else {
		//打开cmd执行
		start(os.Stdin, os.Stdout)
	}

}

// 终端中运行
func start(in io.Reader, out io.Writer) {
	//异常管理
	// exceptionManager := exception.NewExceptionManager(true)
	// exceptionManager.Handle()

	scanner := bufio.NewScanner(in)

	errorManager := exception.NewErrorManager()
	//创建符号表
	env := object.NewEnvironment()
	evaluator.NewEvaluator(env, errorManager)

	// fmt.Fprintf(out, MONKEY_FACE)
	fmt.Fprintf(out, HEADER)
	for {
		fmt.Fprintf(out, PROMPT)
		scanned := scanner.Scan()
		if !scanned {
			return
		}
		// fmt.Println(scanner.Text())
		// saveLog(scanner.Text())
		args := strings.Split(scanner.Text(), " ")

		switch args[0] {
		case "lark":
			if args[1] == "-v" {
				fmt.Println(HEADER)
			}
		case "clear":
			//清空屏幕
			// fmt.Print("\033[1G")
			cmd := exec.Command("cmd", "/c", "cls")
			cmd.Stdout = os.Stdout
			err := cmd.Run()
			if err != nil {
				log.Fatal(err)
			}
		case "exit":
			//退出
			os.Exit(0)
		default:
			//添加多行输入支持
			input, errs := repl.ReadMultiLine(scanner, out)
			if errs != nil {
				log.Fatal(errs)
			}

			//在终端中输入源码，生成临时main.la文件
			// 2. 创建临时文件作为主模块
			// C:\Users\vteip\AppData\Local\Temp\main.la
			tempDir := os.TempDir()
			defer os.RemoveAll(tempDir) // 程序结束时清理临时文件
			// main.la文件不用加后缀
			mainFilePath := filepath.Join(tempDir, "main.la")
			err := os.WriteFile(mainFilePath, []byte(input), 0644)
			if err != nil {
				fmt.Printf("写入临时文件失败: %v\n", err)
				os.Exit(1)
			}
			// fmt.Println("临时文件路径:", mainFilePath)
			// 运行
			// result := Run(scanner.Text(), env, mainFilePath)
			result := Run(mainFilePath, env, "cmd", errorManager)
			if !result {
				continue
			}

		}
	}

}

// 运行
func Run(mainFilePath string, env *object.Environment, runType string, errorManager *exception.ErrorHandler) bool {
	/* // 创建模块加载器，搜索路径为当前目录
	module := loader.NewModuleLoader([]string{"."}, env)
	// 加载被导入的模块
	_, err := module.LoadModule(mainFilePath)
	if err != nil {
		fmt.Println("main_err:", err)
	} */
	// fmt.Println("加载模块:", importedModule)

	// 读取文件内容
	source, err := os.ReadFile(mainFilePath)
	if err != nil {
		return false
	}

	// exceptionManager := exception.NewExceptionManager(true)

	// 词法分析
	lex := lexer.New(string(source))
	p := parser.New(lex)
	p.ErrorHandler = errorManager
	/* //循环打印token
	for tok := lex.NextToken(); tok.Type != lexer.EOF; tok = lex.NextToken() {
		fmt.Printf("%+v\n", tok)
	}
	return true */

	program := p.ParseProgram()
	if len(errorManager.ParseErrors) != 0 {
		fmt.Println(errorManager.FormatErrors())
		return false
	}

	evaluated := evaluator.Eval(program, env)
	//fmt.Printf("%#v\n", evaluated)
	if evaluated != nil {
		evaluated.Inspect()
		if val, ok := evaluated.(*object.Error); ok {
			fmt.Println("main_err:", val.Message)
			// exceptionManager.Handle(val)
			errorManager.FormatErrors()
		}
	}

	return true
}
